<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/works/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/works/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/works/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/works/images/logo.svg" color="#222">

<link rel="stylesheet" href="/works/css/main.css">

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Consolas:300,300italic,400,400italic,700,700italic|PingFang SC:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext">
<link rel="stylesheet" href="/works/lib/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.css">
  <link rel="stylesheet" href="/works/lib/pace/pace-theme-bounce.min.css">
  <script src="/works/lib/pace/pace.min.js"></script>

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"chudod.gitee.io","root":"/works/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"hide","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":true,"scrollpercent":true},"bookmark":{"enable":true,"color":"#222","save":"auto"},"fancybox":true,"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"manual","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":true,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="本篇为小王同学的第3篇操作系统知识：Linux程序执行过程（ELF文件格式）以及进程创建(fork与execve系统调用)">
<meta property="og:type" content="article">
<meta property="og:title" content="Linux程序执行与进程创建">
<meta property="og:url" content="https://chudod.gitee.io/works/2022/05/06/OS_ELF_execve/index.html">
<meta property="og:site_name" content="Computing Dynamics">
<meta property="og:description" content="本篇为小王同学的第3篇操作系统知识：Linux程序执行过程（ELF文件格式）以及进程创建(fork与execve系统调用)">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEB680b0b8f4b6098490039e8f6a025de95?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEBc958d4e5ba53bf36d8f1c91908b8483c?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEB220b71cadf3b1b5bac4278836e4a0316?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEB3721974e0a188301cfda36c6af2c619f?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEB57c257d4ead121d8bc11a07729ae3391?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEBbf788e3c7683fe13a889e12fcb327420?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEBeba8d4cdae87b5cff22f3f2d04def660?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEBa0ad675812fc28302e56120229572181?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEBa5e38da11d4ff698e0aa0010fc73d156?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="og:image" content="https://note.youdao.com/yws/api/personal/file/WEBaa532b54422051cd4217f2017b02d9ec?method=download&shareKey=69113f8f61e335d1864757cf6d288929">
<meta property="article:published_time" content="2022-05-05T16:00:00.000Z">
<meta property="article:modified_time" content="2022-05-24T14:22:01.598Z">
<meta property="article:author" content="虎王">
<meta property="article:tag" content="操作系统">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://note.youdao.com/yws/api/personal/file/WEB680b0b8f4b6098490039e8f6a025de95?method=download&shareKey=69113f8f61e335d1864757cf6d288929">

<link rel="canonical" href="https://chudod.gitee.io/works/2022/05/06/OS_ELF_execve/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>Linux程序执行与进程创建 | Computing Dynamics</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/works/rss2.xml" title="Computing Dynamics" type="application/rss+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/works/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Computing Dynamics</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">小王同学的工作站</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/works/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/works/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/works/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/works/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/works/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
        <li class="menu-item menu-item-schedule">

    <a href="/works/schedule/" rel="section"><i class="fa fa-calendar fa-fw"></i>日程表</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container"></div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="algolia-results">
  <div id="algolia-stats"></div>
  <div id="algolia-hits"></div>
  <div id="algolia-pagination" class="algolia-pagination"></div>
</div>

      
    </div>
  </div>

</div>
    </header>

    
  <div class="reading-progress-bar"></div>
  <a role="button" class="book-mark-link book-mark-link-fixed"></a>

  <a href="https://github.com/Chu-DoD" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://chudod.gitee.io/works/2022/05/06/OS_ELF_execve/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/works/images/avatar.png">
      <meta itemprop="name" content="虎王">
      <meta itemprop="description" content="喜欢造飞机导弹和计算机的大学生">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Computing Dynamics">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Linux程序执行与进程创建
        </h1>

        <div class="post-meta">

        
          <i class="fa fa-thumb-tack"></i>
          <font color=7D26CD>置顶</font>
          <span class="post-meta-divider">|</span>
        
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-05-06 00:00:00" itemprop="dateCreated datePublished" datetime="2022-05-06T00:00:00+08:00">2022-05-06</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-05-24 22:22:01" itemprop="dateModified" datetime="2022-05-24T22:22:01+08:00">2022-05-24</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/works/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/" itemprop="url" rel="index"><span itemprop="name">计算机基础知识</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/works/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" itemprop="url" rel="index"><span itemprop="name">操作系统</span></a>
                </span>
            </span>

          
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>
            <div class="post-description">本篇为小王同学的第3篇操作系统知识：Linux程序执行过程（ELF文件格式）以及进程创建(fork与execve系统调用)</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="一、程序的编译与执行"><a href="#一、程序的编译与执行" class="headerlink" title="一、程序的编译与执行"></a>一、程序的编译与执行</h1><h2 id="Program-Header"><a href="#Program-Header" class="headerlink" title="Program Header"></a>Program Header</h2><p>通常，我们写的代码都是编译、链接一气呵成，直接生成可执行文件，并且程序编译出来的虚拟起始地址通常是0x08048000，操作系统做了很多工作。例如将program.c编译和链接成可运行的文件:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc program.c -o program</span><br></pre></td></tr></table></figure>
<p>这其中经过了编译和链接两个步骤：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc program.c -o program.o</span><br><span class="line">gcc program.o -o program</span><br></pre></td></tr></table></figure>
<p>得到的program.o只是一个待重定位文件，文件里面的符号（函数和变量）还没有安排地址，将来在链接的时候与其他文件“组合”成一个可执行文件时再重新定位（安排地址）。“组合”指的就是链接。因为在编译期间不知道会链接那些文件，所以干脆在链接的阶段一起编址，形成一个可重定位文件。<br>程序之间调用的最简单的方式是$\verb+call+$和$\verb+jmp+$，例如BIOS调用MBR以及MBR调用Loader，MBR的物理地址是0x7c00，而Loader的地址可以是0x900，通常事先约定好调用地址。这种方法非常不灵活，因此一种灵活的方法便是程序的入口地址信息与程序绑定，在程序文件中专门腾出一个空间来写程序的入口地址、程序的大小等等信息。原先的可执行二进制文件(program body)加上新的文件头(program header)，就形成了一种新的文件格式这种具有程序头文件格式的程序文件从外存读入内存中后，从该程序文件的头读出程序入口地址，跨过程序头，跳转到入口地址执行。</p>
<h2 id="ELF文件格式"><a href="#ELF文件格式" class="headerlink" title="ELF文件格式"></a>ELF文件格式</h2><h3 id="ELF文件格式整体视图"><a href="#ELF文件格式整体视图" class="headerlink" title="ELF文件格式整体视图"></a>ELF文件格式整体视图</h3><p>Windows系统下的可执行文件格式是PE（Portable Executable，exe是文件拓展名，不是真正的格式），而Linux的可执行文件格式是ELF(Executable and Linkable Format，可执行连接格式)。ELF文件是经过编译和链接之后，可以直接运行的二进制可执行文件。Linux中的.o文件和可执行二进制文件都是ELF格式的文件。ELF文件格式可以在&#x2F;usr&#x2F;include&#x2F;elf.h中可以找到ELF文件格式的所有定义。<br>程序最重要的概念是段(segment)和节(section)，其中section是程序员在进行汇编程序设计时显示划分出的数据区、代码区、栈区等等，而不同程序在链接时，链接器将多个目标文件相同属性的section链接成一个segment，形成了可执行内存空间中的数据段、代码段等等。因此ELF格式重要有相应的数据结构来描述程序中不同的section和segment，一个段头(Program header，也叫程序头)用来描述一个段，一个节头(Section header)用来描述一个section，也就有了程序头表(Program header table，也可以称之为段头表)和节头表(Section header table)，本质就是用来分别存储段头和节头的两个数组。而程序头表和节头表的条目个数和表长也是不确定的，因此还需要另一个结构来描述程序头表和节头表，也就是ELF头(ELF Header)，因此整个ELF文件格式看起来如下图所示（图片来源：《操作系统真相还原》）。ELF文件格式真正的作用在链接和运行阶段，因此ELF文件格式布局也从这两方面展示。</p>
<head>
    <meta charset="utf-8">
<style>
    .body{width:350px;height:200px}
</style>
<h4 align="center">ELF文件格式视图</h4>
<table align="center" border="1" width="700px" cellspacing="7">
<tr>
    <td style="border: 1px solid black" align="center">链接视图</td>
    <td style="border: 1px solid black" align="center">运行视图</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">ELF Header(elf头)</td>
    <td style="border: 1px solid black" align="center">ELF Header(elf头)</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">Program Header Table(程序头表，非必须，可选)</td>
    <td style="border: 1px solid black" align="center">Program Header Table(程序头表)</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">Section 1(节 1)</td>
    <td style="border: 1px solid black" rowspan="2" align="center">Segment 1(段1)</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">...</th>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">...</th>
    <td style="border: 1px solid black" rowspan="2" align="center">Segment 2(段2)</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">Section n(节 n)</th>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">...</th>
    <td style="border: 1px solid black" align="center">...</th>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">Section Header Table(程序头表)</td>
    <td style="border: 1px solid black" align="center">Section Header Table(程序头表，非必须，可选)</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">...</th>
    <td style="border: 1px solid black" align="center">...</th>
</tr>
<tr>
    <td class="body" style="border: 1px solid black" align="center">带重定位文件体(Program Body)</td>
    <td class="body" style="border: 1px solid black" align="center">可执行文件体(Program Body)</td>
</tr>
</table>

<h3 id="ELF-Header数据结构"><a href="#ELF-Header数据结构" class="headerlink" title="ELF Header数据结构"></a>ELF Header数据结构</h3><p>ELF Header结构定义在&#x2F;usr&#x2F;include&#x2F;elf.h中的$\verb+struct Elf32_Ehdr+$中，结构体定义如下所示：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">unsigned</span> <span class="type">char</span>	e_ident[EI_NIDENT];	    <span class="comment">/* Magic number and other info */</span></span><br><span class="line">  Elf32_Half	e_type;			        <span class="comment">/* Object file type */</span></span><br><span class="line">  Elf32_Half	e_machine;		        <span class="comment">/* Architecture */</span></span><br><span class="line">  Elf32_Word	e_version;		        <span class="comment">/* Object file version */</span></span><br><span class="line">  Elf32_Addr    e_entry;		        <span class="comment">/* Entry point virtual address */</span></span><br><span class="line">  Elf32_Off     e_phoff;		        <span class="comment">/* Program header table file offset */</span></span><br><span class="line">  Elf32_Off     e_shoff;		        <span class="comment">/* Section header table file offset */</span></span><br><span class="line">  Elf32_Word	e_flags;		        <span class="comment">/* Processor-specific flags */</span></span><br><span class="line">  Elf32_Half	e_ehsize;		        <span class="comment">/* ELF header size in bytes */</span></span><br><span class="line">  Elf32_Half	e_phentsize;		    <span class="comment">/* Program header table entry size */</span></span><br><span class="line">  Elf32_Half	e_phnum;		        <span class="comment">/* Program header table entry count */</span></span><br><span class="line">  Elf32_Half	e_shentsize;		    <span class="comment">/* Section header table entry size */</span></span><br><span class="line">  Elf32_Half	e_shnum;		        <span class="comment">/* Section header table entry count */</span></span><br><span class="line">  Elf32_Half	e_shstrndx;		        <span class="comment">/* Section header string table index */</span></span><br><span class="line">&#125; Elf32_Ehdr;</span><br></pre></td></tr></table></figure>
<p>其中e_ident[16]是16字节大小的数组，用来表示魔数以及其他的信息，具体含义如下表所示。</p>
<head>
    <meta charset="utf-8">
<style>
    .leftbody{width:300px;height:100px}
    .rightbody{width:400px;height:100px}
</style>
<h4 align="center">e_ident[16]数组</h4>
<table align="center" border="1" width="700px" cellspacing="7">
<tr>
    <td style="border: 1px solid black" align="center">e_ident[]成员</td>
    <td style="border: 1px solid black" align="center">意义</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[0] = 0x7f</td>
    <td style="border: 1px solid black" rowspan="4" align="center">这4位是ELF文件的魔数(magic number)，表明这是一个ELF文件，e_ident[1]~e_ident[3]这3个变量表示‘E’、‘L’、‘F’这三个字符</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[1] = 'E'</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[2] = 'L'</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[3] = 'F'</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[4]</td>
    <td style="border: 1px solid black" align="center">ELF文件类型，值为0表示不可识别，值为1表示32位elf文件，值2表示64位elf文件</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[5]</td>
    <td style="border: 1px solid black" align="center">编码格式，值为0：非法编码，值为1：小端字节序LSB，值为2：大端字节序MSB</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[6]</td>
    <td style="border: 1px solid black" align="center">版本信息，默认为1</td>
</tr>
<tr>
    <td class="leftbody" style="border: 1px solid black" align="center">e_ident[7～15]</td>
    <td class="rightbody" style="border: 1px solid black" align="center">保留位，初始化为0</td>
</tr>
</table>

<p>而$\verb+struct Elf32_Ehdr+$中的所有成员的定义如下：</p>
<head>
    <meta charset="utf-8">
<style>
    .leftbody{width:200px;height:30px}
    .rightbody{width:500px;height:30px}
</style>
<h4 align="center">struct Elf32_Ehdr成员定义</h4>
<table align="center" border="1" width="700px" cellspacing="7">
<tr>
    <td style="border: 1px solid black" align="center">e_ident[16]</td>
    <td style="border: 1px solid black" align="center">魔数和其他信息</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_type</td>
    <td style="border: 1px solid black" align="center">2字节，目标文件类型，值0：位置格式文件，值1：可重定位文件，值2：可执行文件，值3：动态共享目标文件，值4：core文件（程序崩溃时内存映像转储格式），其他值无需关注</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_machine</td>
    <td style="border: 1px solid black" align="center">2字节，elf文件所属体系结构，值2：SPARC，值3：Intel 80386，值7：Intel 80860，值8：MPIS RS3000等等</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_version</td>
    <td style="border: 1px solid black" align="center">4字节，版本信息</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_entry</td>
    <td style="border: 1px solid black" align="center">4字节，操作系统运行该程序时，将控制权转交到的虚拟地址</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_phoff</td>
    <td style="border: 1px solid black" align="center">4字节，程序头表(program header table)在文件内的字节偏移量，若没有程序头表，则该值为0</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_shoff</td>
    <td style="border: 1px solid black" align="center">4字节，节头表(section header table)在文件内的字节偏移量，若没有节头表，则该值为0</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_flags</td>
    <td style="border: 1px solid black" align="center">4字节，处理器相关的标志</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ehsize</td>
    <td style="border: 1px solid black" align="center">2字节，elf header的字节大小</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_phentsize</td>
    <td style="border: 1px solid black" align="center">2字节，程序头表(program header table)的每个条目(entry)的字节大小，该条目就是后面将要引出的struct Elf32_Phdr</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_phnum</td>
    <td style="border: 1px solid black" align="center">2字节，程序头表(program header table)的条目(entry)个数，即程序中有多少个段</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_shentsize</td>
    <td style="border: 1px solid black" align="center">2字节，节头表(section header table)的每个条目的字节大小</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_shnum</td>
    <td style="border: 1px solid black" align="center">2字节，节头表(section header table)的条目个数</td>
</tr>
<tr>
    <td class="leftbody" style="border: 1px solid black" align="center">e_shstrndx</td>
    <td class="leftbody" style="border: 1px solid black" align="center">2字节，Section header string table在节头表中的索引</td>
</tr>
</table>

<p>接下来是程序头表中条目的数据结构，也就是用来描述各个段(segment)的信息，其结构体为$\verb+struct Elf32_Phdr+$，如下所示：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Program segment header.  */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span></span><br><span class="line">&#123;</span><br><span class="line">  Elf32_Word	p_type;			<span class="comment">/* Segment type */</span></span><br><span class="line">  Elf32_Off	    p_offset;		<span class="comment">/* Segment file offset */</span></span><br><span class="line">  Elf32_Addr	p_vaddr;		<span class="comment">/* Segment virtual address */</span></span><br><span class="line">  Elf32_Addr	p_paddr;		<span class="comment">/* Segment physical address */</span></span><br><span class="line">  Elf32_Word	p_filesz;		<span class="comment">/* Segment size in file */</span></span><br><span class="line">  Elf32_Word	p_memsz;		<span class="comment">/* Segment size in memory */</span></span><br><span class="line">  Elf32_Word	p_flags;		<span class="comment">/* Segment flags */</span></span><br><span class="line">  Elf32_Word	p_align;		<span class="comment">/* Segment alignment */</span></span><br><span class="line">&#125; Elf32_Phdr;</span><br></pre></td></tr></table></figure>
<p>结构体中的各个成员的信息如下表所示：</p>
<head>
    <meta charset="utf-8">
<style>
    .leftbody{width:200px;height:30px}
    .rightbody{width:500px;height:30px}
</style>
<h4 align="center">struct Elf32_Phdr成员定义</h4>
<table align="center" border="1" width="700px" cellspacing="7">
<tr>
    <td style="border: 1px solid black" align="center">p_type</td>
    <td style="border: 1px solid black" align="center">4字节，表示程序中该段的类型，值1：可加载程序段，值2：动态链接信息，值3：动态加载器名称，值6：程序头表，以及其他无需关注的信息</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_offset</td>
    <td style="border: 1px solid black" align="center">4字节，本段在文件内的起始偏移地址</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_vaddr</td>
    <td style="border: 1px solid black" align="center">4字节，本段在内存中的起始虚拟地址</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_paddr</td>
    <td style="border: 1px solid black" align="center">4字节，仅用于与物理地址相关的系统如System V中</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_filesz</td>
    <td style="border: 1px solid black" align="center">4字节，本段在文件中的大小</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_memsz</td>
    <td style="border: 1px solid black" align="center">4字节，本段在内存中的大小</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_flags</td>
    <td style="border: 1px solid black" align="center">4字节，本段相关的标志，0b1：可执行，0b10：可写，0b100：可读，以及其他标志</td>
</tr>
<tr>
    <td class="leftbody" style="border: 1px solid black" align="center">p_align</td>
    <td class="rightbody" style="border: 1px solid black" align="center">4字节，本段在内存和文件中的对齐方式，若值为0或值1，则不对齐，否则其为2的幂次</td>
</tr>
</table>

<h3 id="实验程序实例"><a href="#实验程序实例" class="headerlink" title="实验程序实例"></a>实验程序实例</h3><p>一共两个程序，分别为parent.c和child.c，其中在parent.c中父进程会$\verb+fork+$一个子进程，子进程会利用$\verb+execve+$系统调用来将child.c加载进自己的进程空间，执行这一段新的程序。<br>这个是父进程执行的程序：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*parent.c*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">char</span> str1[<span class="number">4096</span>] = &#123;<span class="string">&quot;String of parent process.\n&quot;</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">pid_t</span> pid;</span><br><span class="line">    pid = fork();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(pid &lt; <span class="number">0</span>)             <span class="comment">/*Error occured*/</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">fprintf</span>(stderr, <span class="string">&quot;Fork failed!\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(pid == <span class="number">0</span>)            <span class="comment">/*Child process*/</span></span><br><span class="line">    &#123;</span><br><span class="line">	    <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, str1);</span><br><span class="line">        <span class="built_in">strcpy</span>(str1, <span class="string">&quot;String of child process.\n&quot;</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, str1);</span><br><span class="line">        <span class="built_in">execve</span>(<span class="string">&quot;./child&quot;</span>, <span class="literal">NULL</span>, <span class="literal">NULL</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span>                    <span class="comment">/*Parent process*/</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">wait</span>(<span class="literal">NULL</span>);</span><br><span class="line">	    <span class="built_in">strcpy</span>(str1, <span class="string">&quot;Running in parent process.\n&quot;</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, str1);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这个是子进程加载的新程序：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*child.c*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">char</span> str2[<span class="number">4096</span>] = &#123;<span class="string">&quot;Child process is runing another program!\n&quot;</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">char</span>* ptr2 = (<span class="type">char</span>*)<span class="built_in">malloc</span>(<span class="built_in">sizeof</span>(<span class="type">char</span>) * (<span class="built_in">strlen</span>(str2) + <span class="number">1</span>));</span><br><span class="line">    <span class="built_in">memset</span>(ptr2, <span class="number">0</span>, <span class="built_in">sizeof</span>(ptr2));</span><br><span class="line">    <span class="built_in">strcpy</span>(ptr2, str2);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, ptr2);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="ELF-Header实例"><a href="#ELF-Header实例" class="headerlink" title="ELF Header实例"></a>ELF Header实例</h3><p>可以利用xxd命令来查看ELF文件格式信息，新建一个xxd.sh脚本，其内容为：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xxd -g <span class="number">1</span> -s $<span class="number">2</span> -l $<span class="number">3</span> $<span class="number">1</span></span><br></pre></td></tr></table></figure>
<p>然后在命令行中输入</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sh ./xxd.sh ./child <span class="number">0</span> <span class="number">300</span></span><br></pre></td></tr></table></figure>
<p>即可查看child文件的ELF格式信息。上面参数的意思是查看0~300字节的ELF文件格式信息。在学校提供的实验平台上得到的结果如下所示：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">00000000</span>: <span class="number">7f</span> <span class="number">45</span> <span class="number">4</span>c <span class="number">46</span> <span class="number">01</span> <span class="number">01</span> <span class="number">01</span> <span class="number">03</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  .ELF............</span><br><span class="line"><span class="number">00000010</span>: <span class="number">02</span> <span class="number">00</span> <span class="number">03</span> <span class="number">00</span> <span class="number">01</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">0</span>a <span class="number">8</span>d <span class="number">04</span> <span class="number">08</span> <span class="number">34</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  ...........<span class="number">.4</span>...</span><br><span class="line"><span class="number">00000020</span>: <span class="number">0</span>c <span class="number">34</span> <span class="number">0</span>a <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">34</span> <span class="number">00</span> <span class="number">20</span> <span class="number">00</span> <span class="number">06</span> <span class="number">00</span> <span class="number">28</span> <span class="number">00</span>  <span class="number">.4</span>.....<span class="number">.4</span>. ...(.</span><br><span class="line"><span class="number">00000030</span>: <span class="number">24</span> <span class="number">00</span> <span class="number">21</span> <span class="number">00</span> <span class="number">01</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">80</span> <span class="number">04</span> <span class="number">08</span>  $.!.............</span><br><span class="line"><span class="number">00000040</span>: <span class="number">00</span> <span class="number">80</span> <span class="number">04</span> <span class="number">08</span> <span class="number">6f</span> <span class="number">00</span> <span class="number">0</span>a <span class="number">00</span> <span class="number">6f</span> <span class="number">00</span> <span class="number">0</span>a <span class="number">00</span> <span class="number">05</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  ....o...o.......</span><br><span class="line"><span class="number">00000050</span>: <span class="number">00</span> <span class="number">10</span> <span class="number">00</span> <span class="number">00</span> <span class="number">01</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">58</span> <span class="number">0f</span> <span class="number">0</span>a <span class="number">00</span> <span class="number">58</span> <span class="number">9f</span> <span class="number">0</span>e <span class="number">08</span>  ........X...X...</span><br><span class="line"><span class="number">00000060</span>: <span class="number">58</span> <span class="number">9f</span> <span class="number">0</span>e <span class="number">08</span> <span class="number">48</span> <span class="number">20</span> <span class="number">00</span> <span class="number">00</span> cc <span class="number">33</span> <span class="number">00</span> <span class="number">00</span> <span class="number">06</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  X...H ..<span class="number">.3</span>......</span><br><span class="line"><span class="number">00000070</span>: <span class="number">00</span> <span class="number">10</span> <span class="number">00</span> <span class="number">00</span> <span class="number">04</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> f4 <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> f4 <span class="number">80</span> <span class="number">04</span> <span class="number">08</span>  ................</span><br><span class="line"><span class="number">00000080</span>: f4 <span class="number">80</span> <span class="number">04</span> <span class="number">08</span> <span class="number">44</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">44</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">04</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  ....D...D.......</span><br><span class="line"><span class="number">00000090</span>: <span class="number">04</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">07</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">58</span> <span class="number">0f</span> <span class="number">0</span>a <span class="number">00</span> <span class="number">58</span> <span class="number">9f</span> <span class="number">0</span>e <span class="number">08</span>  ........X...X...</span><br><span class="line"><span class="number">000000</span>a0: <span class="number">58</span> <span class="number">9f</span> <span class="number">0</span>e <span class="number">08</span> <span class="number">10</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">28</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">04</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  X.......(.......</span><br><span class="line"><span class="number">000000b</span>0: <span class="number">04</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">51</span> e5 <span class="number">74</span> <span class="number">64</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  ....Q.td........</span><br><span class="line"><span class="number">000000</span>c0: <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">06</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  ................</span><br><span class="line"><span class="number">000000</span>d0: <span class="number">10</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">52</span> e5 <span class="number">74</span> <span class="number">64</span> <span class="number">58</span> <span class="number">0f</span> <span class="number">0</span>a <span class="number">00</span> <span class="number">58</span> <span class="number">9f</span> <span class="number">0</span>e <span class="number">08</span>  ....R.tdX...X...</span><br><span class="line"><span class="number">000000e0</span>: <span class="number">58</span> <span class="number">9f</span> <span class="number">0</span>e <span class="number">08</span> a8 <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> a8 <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">04</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  X...............</span><br><span class="line"><span class="number">000000f</span>0: <span class="number">01</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">04</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">10</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">01</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  ................</span><br><span class="line"><span class="number">00000100</span>: <span class="number">47</span> <span class="number">4</span>e <span class="number">55</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">02</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">06</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  GNU.............</span><br><span class="line"><span class="number">00000110</span>: <span class="number">18</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">04</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">14</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">03</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>  ................</span><br><span class="line"><span class="number">00000120</span>: <span class="number">47</span> <span class="number">4</span>e <span class="number">55</span> <span class="number">00</span> d9 <span class="number">5</span>e <span class="number">23</span> cf b2 <span class="number">2</span>c <span class="number">61</span> f1              GNU..^#..,a.</span><br></pre></td></tr></table></figure>
<p>因此child文件的ELF格式信息具体含义如下，其中0x00到0x33号内存单元是ELF Header(即$\verb+struct Elf+$)的内容，0x34到0xf4为program header(即$\verb+struct Elf32_Phdr+$)的内容，首先分析ELF Header信息：</p>
<head>
    <meta charset="utf-8">
<style>
    .leftbody{width:150px;height:30px}
    .midbody{width:150;height:300}
    .rightbody{width:400px;height:30px}
</style>
<h4 align="center">child文件的ELF Header信息</h4>
<table align="center" border="1" width="700px" cellspacing="7">
<tr>
    <td style="border: 1px solid black" align="center">成员</td>
    <td style="border: 1px solid black" align="center">值</td>
    <td style="border: 1px solid black" align="center">含义</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[4]</td>
    <td style="border: 1px solid black" align="center">0x01</td>
    <td style="border: 1px solid black" align="center">32位的elf文件</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ident[5]</td>
    <td style="border: 1px solid black" align="center">0x01</td>
    <td style="border: 1px solid black" align="center">小端字节序</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_type</td>
    <td style="border: 1px solid black" align="center">0x0002</td>
    <td style="border: 1px solid black" align="center">可执行文件</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_machine</td>
    <td style="border: 1px solid black" align="center">0x0003</td>
    <td style="border: 1px solid black" align="center">intel 80386平台</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_entry</td>
    <td style="border: 1px solid black" align="center">0x08048d0a</td>
    <td style="border: 1px solid black" align="center">程序的虚拟入口地址为0x08048d0a</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_phoff</td>
    <td style="border: 1px solid black" align="center">0x00000034</td>
    <td style="border: 1px solid black" align="center">程序头表在文件中的偏移量是0x34</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_shoff</td>
    <td style="border: 1px solid black" align="center">0x000a340c</td>
    <td style="border: 1px solid black" align="center">节头表在文件中的偏移量</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_ehsize</td>
    <td style="border: 1px solid black" align="center">0x0034</td>
    <td style="border: 1px solid black" align="center">elf header大小为0x34，可见程序头表后面跟着elf头</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_phentsize</td>
    <td style="border: 1px solid black" align="center">0x0020</td>
    <td style="border: 1px solid black" align="center">程序头表program header每个条目(struct Elf32_Phdr)的大小为0x20</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_phnum</td>
    <td style="border: 1px solid black" align="center">0x0006</td>
    <td style="border: 1px solid black" align="center">程序头表中的元素个数为6，即有6个段</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_shentsize</td>
    <td style="border: 1px solid black" align="center">0x0028</td>
    <td style="border: 1px solid black" align="center">节头表中各个节的大小</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">e_shnum</td>
    <td style="border: 1px solid black" align="center">0x0024</td>
    <td style="border: 1px solid black" align="center">节头表中元素个数，说明一共0x24=36个节</td>
</tr>
<tr>
    <td class="leftbody" style="border: 1px solid black" align="center">e_shstrndx</td>
    <td class="midbody" style="border: 1px solid black" align="center">0x0021</td>
    <td class="rightbody" style="border: 1px solid black" align="center">string name table在节头表中的索引为0x21</td>
</tr>
</table>

<p>然后分析程序头表program header的内容(第4行的0x34开始)，刚才ELF Header中可以知道，程序一共有6个段，且每个段的条目的大小为0x20。</p>
<head>
    <meta charset="utf-8">
<style>
    .leftbody{width:150px;height:30px}
    .midbody{width:150;height:300}
    .rightbody{width:400px;height:30px}
</style>
<h4 align="center">child文件的Program Header信息</h4>
<table align="center" border="1" width="700px" cellspacing="7">
<tr>
    <td style="border: 1px solid black" align="center">成员</td>
    <td style="border: 1px solid black" align="center">值</td>
    <td style="border: 1px solid black" align="center">含义</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_type</td>
    <td style="border: 1px solid black" align="center">0x00000001</td>
    <td style="border: 1px solid black" align="center">该程序为可加载程序段</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_offset</td>
    <td style="border: 1px solid black" align="center">0x00000000</td>
    <td style="border: 1px solid black" align="center">本段在文件内的偏移量为0x00</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_vaddr</td>
    <td style="border: 1px solid black" align="center">0x08048000</td>
    <td style="border: 1px solid black" align="center">该段被加载到内存后的起始虚拟地址！Elf Header中的e_entry是整个程序的入口地址(0x08048d0a)，而整个程序的起始地址是0x08048000。</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_paddr</td>
    <td style="border: 1px solid black" align="center">0x08048000</td>
    <td style="border: 1px solid black" align="center">和p_vaddr相似，不用管这个</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_filesz</td>
    <td style="border: 1px solid black" align="center">0x000a006f</td>
    <td style="border: 1px solid black" align="center">本段在文件中的字节大小</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_memsz</td>
    <td style="border: 1px solid black" align="center">0x000a006f</td>
    <td style="border: 1px solid black" align="center">本段在内存中的字节大小，等于p_filesz</td>
</tr>
<tr>
    <td style="border: 1px solid black" align="center">p_flags</td>
    <td style="border: 1px solid black" align="center">0x00000005</td>
    <td style="border: 1px solid black" align="center">5=4+1，因此该段可读可执行，据此推测出该段应该是代码段。</td>
</tr>
<tr>
    <td class="leftbody" style="border: 1px solid black" align="center">p_align</td>
    <td class="midbody" style="border: 1px solid black" align="center">0x00001000</td>
    <td class="rightbody" style="border: 1px solid black" align="center">本段的对齐方式为32字节对齐</td>
</tr>
</table>

<p>接下来看数据段的信息，在gdb调试窗口中打印str2的地址，为0x80ea080，并且数据段线性区的地址范围为0x80e9000到0x80ec000。<br>除了利用xxd命令查看ELF文件格式外，还可以利用readelf命令来查看。简单的输入：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">readelf -e child</span><br></pre></td></tr></table></figure>
<p>即可得到如下信息：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line">ELF Header:</span><br><span class="line">  Magic:   <span class="number">7f</span> <span class="number">45</span> <span class="number">4</span>c <span class="number">46</span> <span class="number">01</span> <span class="number">01</span> <span class="number">01</span> <span class="number">03</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span></span><br><span class="line">  Class:                             ELF32</span><br><span class="line">  Data:                              <span class="number">2&#x27;</span>s complement, little endian</span><br><span class="line">  Version:                           <span class="number">1</span> (current)</span><br><span class="line">  OS/ABI:                            UNIX - GNU</span><br><span class="line">  ABI Version:                       <span class="number">0</span></span><br><span class="line">  Type:                              <span class="built_in">EXEC</span> (Executable file)</span><br><span class="line">  Machine:                           Intel <span class="number">80386</span></span><br><span class="line">  Version:                           <span class="number">0x1</span></span><br><span class="line">  Entry point address:               <span class="number">0x8048d0a</span></span><br><span class="line">  Start of program headers:          <span class="number">52</span> (bytes into file)</span><br><span class="line">  Start of section headers:          <span class="number">668684</span> (bytes into file)</span><br><span class="line">  Flags:                             <span class="number">0x0</span></span><br><span class="line">  Size of <span class="keyword">this</span> header:               <span class="number">52</span> (bytes)</span><br><span class="line">  Size of program headers:           <span class="number">32</span> (bytes)</span><br><span class="line">  Number of program headers:         <span class="number">6</span></span><br><span class="line">  Size of section headers:           <span class="number">40</span> (bytes)</span><br><span class="line">  Number of section headers:         <span class="number">36</span></span><br><span class="line">  Section header string table index: <span class="number">33</span></span><br><span class="line"></span><br><span class="line">Section Headers:</span><br><span class="line">  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al</span><br><span class="line">  [ <span class="number">0</span>]                   <span class="literal">NULL</span>            <span class="number">00000000</span> <span class="number">000000</span> <span class="number">000000</span> <span class="number">00</span>      <span class="number">0</span>   <span class="number">0</span>  <span class="number">0</span></span><br><span class="line">  [ <span class="number">1</span>] .note.ABI-tag     NOTE            <span class="number">080480f</span>4 <span class="number">0000f</span>4 <span class="number">000020</span> <span class="number">00</span>   A  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [ <span class="number">2</span>] .note.gnu.build-i NOTE            <span class="number">08048114</span> <span class="number">000114</span> <span class="number">000024</span> <span class="number">00</span>   A  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [ <span class="number">3</span>] .rel.plt          REL             <span class="number">08048138</span> <span class="number">000138</span> <span class="number">000070</span> <span class="number">08</span>   A  <span class="number">0</span>   <span class="number">5</span>  <span class="number">4</span></span><br><span class="line">  [ <span class="number">4</span>] .init             PROGBITS        <span class="number">080481</span>a8 <span class="number">0001</span>a8 <span class="number">000023</span> <span class="number">00</span>  AX  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [ <span class="number">5</span>] .plt              PROGBITS        <span class="number">080481</span>d0 <span class="number">0001</span>d0 <span class="number">0000e0</span> <span class="number">00</span>  AX  <span class="number">0</span>   <span class="number">0</span> <span class="number">16</span></span><br><span class="line">  [ <span class="number">6</span>] .text             PROGBITS        <span class="number">080482b</span>0 <span class="number">0002b</span>0 <span class="number">075134</span> <span class="number">00</span>  AX  <span class="number">0</span>   <span class="number">0</span> <span class="number">16</span></span><br><span class="line">  [ <span class="number">7</span>] __libc_freeres_fn PROGBITS        <span class="number">080b</span>d3f0 <span class="number">0753f</span>0 <span class="number">000</span>ad6 <span class="number">00</span>  AX  <span class="number">0</span>   <span class="number">0</span> <span class="number">16</span></span><br><span class="line">  [ <span class="number">8</span>] __libc_thread_fre PROGBITS        <span class="number">080b</span>ded0 <span class="number">075</span>ed0 <span class="number">00006f</span> <span class="number">00</span>  AX  <span class="number">0</span>   <span class="number">0</span> <span class="number">16</span></span><br><span class="line">  [ <span class="number">9</span>] .fini             PROGBITS        <span class="number">080b</span>df40 <span class="number">075f</span>40 <span class="number">000014</span> <span class="number">00</span>  AX  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">10</span>] .rodata           PROGBITS        <span class="number">080b</span>df60 <span class="number">075f</span>60 <span class="number">01b</span>f90 <span class="number">00</span>   A  <span class="number">0</span>   <span class="number">0</span> <span class="number">32</span></span><br><span class="line">  [<span class="number">11</span>] __libc_subfreeres PROGBITS        <span class="number">080</span>d9ef0 <span class="number">091</span>ef0 <span class="number">00002</span>c <span class="number">00</span>   A  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">12</span>] __libc_atexit     PROGBITS        <span class="number">080</span>d9f1c <span class="number">091f</span>1c <span class="number">000004</span> <span class="number">00</span>   A  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">13</span>] __libc_thread_sub PROGBITS        <span class="number">080</span>d9f20 <span class="number">091f</span>20 <span class="number">000004</span> <span class="number">00</span>   A  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">14</span>] .eh_frame         PROGBITS        <span class="number">080</span>d9f24 <span class="number">091f</span>24 <span class="number">00e0</span>a8 <span class="number">00</span>   A  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">15</span>] .gcc_except_table PROGBITS        <span class="number">080e7</span>fcc <span class="number">09f</span>fcc <span class="number">0000</span>a3 <span class="number">00</span>   A  <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">  [<span class="number">16</span>] .tdata            PROGBITS        <span class="number">080e9</span>f58 <span class="number">0</span>a0f58 <span class="number">000010</span> <span class="number">00</span> WAT  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">17</span>] .tbss             NOBITS          <span class="number">080e9</span>f68 <span class="number">0</span>a0f68 <span class="number">000018</span> <span class="number">00</span> WAT  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">18</span>] .init_array       INIT_ARRAY      <span class="number">080e9</span>f68 <span class="number">0</span>a0f68 <span class="number">000008</span> <span class="number">00</span>  WA  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">19</span>] .fini_array       FINI_ARRAY      <span class="number">080e9</span>f70 <span class="number">0</span>a0f70 <span class="number">000008</span> <span class="number">00</span>  WA  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">20</span>] .jcr              PROGBITS        <span class="number">080e9</span>f78 <span class="number">0</span>a0f78 <span class="number">000004</span> <span class="number">00</span>  WA  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">21</span>] .data.rel.ro      PROGBITS        <span class="number">080e9</span>f80 <span class="number">0</span>a0f80 <span class="number">000070</span> <span class="number">00</span>  WA  <span class="number">0</span>   <span class="number">0</span> <span class="number">32</span></span><br><span class="line">  [<span class="number">22</span>] .got              PROGBITS        <span class="number">080e9</span>ff0 <span class="number">0</span>a0ff0 <span class="number">000008</span> <span class="number">04</span>  WA  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">23</span>] .got.plt          PROGBITS        <span class="number">080</span>ea000 <span class="number">0</span>a1000 <span class="number">000044</span> <span class="number">04</span>  WA  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">24</span>] .data             PROGBITS        <span class="number">080</span>ea060 <span class="number">0</span>a1060 <span class="number">001f</span>40 <span class="number">00</span>  WA  <span class="number">0</span>   <span class="number">0</span> <span class="number">32</span></span><br><span class="line">  [<span class="number">25</span>] .bss              NOBITS          <span class="number">080</span>ebfa0 <span class="number">0</span>a2fa0 <span class="number">00136</span>c <span class="number">00</span>  WA  <span class="number">0</span>   <span class="number">0</span> <span class="number">32</span></span><br><span class="line">  [<span class="number">26</span>] __libc_freeres_pt NOBITS          <span class="number">080</span>ed30c <span class="number">0</span>a2fa0 <span class="number">000018</span> <span class="number">00</span>  WA  <span class="number">0</span>   <span class="number">0</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">27</span>] .comment          PROGBITS        <span class="number">00000000</span> <span class="number">0</span>a2fa0 <span class="number">00002b</span> <span class="number">01</span>  MS  <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">  [<span class="number">28</span>] .debug_aranges    PROGBITS        <span class="number">00000000</span> <span class="number">0</span>a2fcb <span class="number">000020</span> <span class="number">00</span>      <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">  [<span class="number">29</span>] .debug_info       PROGBITS        <span class="number">00000000</span> <span class="number">0</span>a2feb <span class="number">0000</span>dd <span class="number">00</span>      <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">  [<span class="number">30</span>] .debug_abbrev     PROGBITS        <span class="number">00000000</span> <span class="number">0</span>a30c8 <span class="number">0000</span>a0 <span class="number">00</span>      <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">  [<span class="number">31</span>] .debug_line       PROGBITS        <span class="number">00000000</span> <span class="number">0</span>a3168 <span class="number">00004</span>d <span class="number">00</span>      <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">  [<span class="number">32</span>] .debug_str        PROGBITS        <span class="number">00000000</span> <span class="number">0</span>a31b5 <span class="number">0000</span>cb <span class="number">01</span>  MS  <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">  [<span class="number">33</span>] .shstrtab         STRTAB          <span class="number">00000000</span> <span class="number">0</span>a3280 <span class="number">00018</span>c <span class="number">00</span>      <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">  [<span class="number">34</span>] .symtab           SYMTAB          <span class="number">00000000</span> <span class="number">0</span>a39ac <span class="number">008</span>c00 <span class="number">10</span>     <span class="number">35</span> <span class="number">1060</span>  <span class="number">4</span></span><br><span class="line">  [<span class="number">35</span>] .strtab           STRTAB          <span class="number">00000000</span> <span class="number">0</span>ac5ac <span class="number">007</span>ebd <span class="number">00</span>      <span class="number">0</span>   <span class="number">0</span>  <span class="number">1</span></span><br><span class="line">Key to Flags:</span><br><span class="line">  <span class="built_in">W</span> (write), <span class="built_in">A</span> (alloc), <span class="built_in">X</span> (execute), <span class="built_in">M</span> (merge), <span class="built_in">S</span> (strings)</span><br><span class="line">  <span class="built_in">I</span> (info), <span class="built_in">L</span> (link order), <span class="built_in">G</span> (group), <span class="built_in">T</span> (TLS), <span class="built_in">E</span> (exclude), <span class="built_in">x</span> (unknown)</span><br><span class="line">  <span class="built_in">O</span> (extra OS processing required) <span class="built_in">o</span> (OS specific), <span class="built_in">p</span> (processor specific)</span><br><span class="line"></span><br><span class="line">Program Headers:</span><br><span class="line">  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align</span><br><span class="line">  LOAD           <span class="number">0x000000</span> <span class="number">0x08048000</span> <span class="number">0x08048000</span> <span class="number">0xa006f</span> <span class="number">0xa006f</span> R E <span class="number">0x1000</span></span><br><span class="line">  LOAD           <span class="number">0x0a0f58</span> <span class="number">0x080e9f58</span> <span class="number">0x080e9f58</span> <span class="number">0x02048</span> <span class="number">0x033cc</span> RW  <span class="number">0x1000</span></span><br><span class="line">  NOTE           <span class="number">0x0000f4</span> <span class="number">0x080480f4</span> <span class="number">0x080480f4</span> <span class="number">0x00044</span> <span class="number">0x00044</span> R   <span class="number">0x4</span></span><br><span class="line">  TLS            <span class="number">0x0a0f58</span> <span class="number">0x080e9f58</span> <span class="number">0x080e9f58</span> <span class="number">0x00010</span> <span class="number">0x00028</span> R   <span class="number">0x4</span></span><br><span class="line">  GNU_STACK      <span class="number">0x000000</span> <span class="number">0x00000000</span> <span class="number">0x00000000</span> <span class="number">0x00000</span> <span class="number">0x00000</span> RW  <span class="number">0x10</span></span><br><span class="line">  GNU_RELRO      <span class="number">0x0a0f58</span> <span class="number">0x080e9f58</span> <span class="number">0x080e9f58</span> <span class="number">0x000a8</span> <span class="number">0x000a8</span> R   <span class="number">0x1</span></span><br><span class="line"></span><br><span class="line"> Section to Segment mapping:</span><br><span class="line">  Segment Sections...</span><br><span class="line">   <span class="number">00</span>     .note.ABI-tag .note.gnu.build-id .rel.plt .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini .rodata __libc_subfreeres __libc_atexit __libc_thread_subfreeres .eh_frame .gcc_except_table</span><br><span class="line">   <span class="number">01</span>     .tdata .init_array .fini_array .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs</span><br><span class="line">   <span class="number">02</span>     .note.ABI-tag .note.gnu.build-id</span><br><span class="line">   <span class="number">03</span>     .tdata .tbss</span><br><span class="line">   <span class="number">04</span></span><br><span class="line">   <span class="number">05</span>     .tdata .init_array .fini_array .jcr .data.rel.ro .got</span><br></pre></td></tr></table></figure>
<p>上面包含了ELF Header，所有Program Header以及Section Header的信息，最后还指明了每个section会整合进哪一个segment中，可以看到数据段应该是第2个segment。</p>
<h1 id="进程的创建与程序加载"><a href="#进程的创建与程序加载" class="headerlink" title="进程的创建与程序加载"></a>进程的创建与程序加载</h1><h2 id="整体视图"><a href="#整体视图" class="headerlink" title="整体视图"></a>整体视图</h2><p>在shell终端输入.&#x2F;parent，shell进程会调用fork()和execve()来创建新进程并加载.&#x2F;parent文件映像到父进程空间，然后parent进程又会同样调用fork()和execve()来创建新进程并加载.&#x2F;child文件映像到子进程空间。</p>
<div style = "align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEB680b0b8f4b6098490039e8f6a025de95?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="40%" height="40%"/> 

<h2 id="Fork系统调用"><a href="#Fork系统调用" class="headerlink" title="Fork系统调用"></a>Fork系统调用</h2><p>fork函数的原型是$\verb+pid_t fork(void)+$，返回值有3种：子进程pid、0、-1。如果fork失败，那么返回-1。为了让父进程知道自己创建的子进程号，fork会给父进程返回子进程的pid，并且没有pid为0的的进程，因此fork给子进程返回0，通过返回值将父子进程区分开。调用fork之后，子进程会完全拷贝父进程的地址空间，因此两份进程的代码是一样的，只不过子进程是在fork系统调用才开始执行代码的，两者在$if$语句分道扬镳，就像一个叉子一样。<br>在Unix系统中提供了3种创建进程相关的系统调用: fork、vfork和clone，三种系统调用的区别如下：</p>
<table>
<thead>
<tr>
<th align="center">系统调用</th>
<th align="center">区别</th>
</tr>
</thead>
<tbody><tr>
<td align="center">fork</td>
<td align="center">无参数，子进程是父进程完整拷贝：复制父进程所有资源包括地址空间(mm_struct:包含指向页目录表和页表的指针)、页表、打开文件表、信号处理等，新版内核增加了写时复制COW，fork的代价仅剩拷贝父进程页表</td>
</tr>
<tr>
<td align="center">vfork</td>
<td align="center">无参数，父子进程共享地址空间：同一个mm_struct，无需复制，子进程完全运行在父进程的地址空间上，因此子进程修改变量，父进程的变量也会改变。为防止父进程重写子进程需要的数据，阻塞父进程执行，直到子进程退出或者使用exec加载新的程序</td>
</tr>
<tr>
<td align="center">clone</td>
<td align="center">有参数，父进程的资源有选择性的拷贝给子进程：clone_flags参数共享哪些资源，其余资源进行复制</td>
</tr>
</tbody></table>
<p>在调用fork系统调用时，创建的新任务具有父进程的所有相关数据的副本，更高版本的内核增加了写时复制(Copy On Write)，父子进程共享一组资源，例如数据段，设置为只读，如果子进程修改了数据段中的变量，数据段中的内容拷贝到新的内存中再进行修改，因此子进程对变量修改不会影响父进程。调用clone系统调用时，创建的新任务并不具有所有数据的拷贝，clone_flags参数决定共享哪些资源，例如$\verb+CLONE_VM+$决定共享相同的内存空间，$\verb+CLONE_FILES+$决定共享相同的打开文件。如果不设置这些参数，那么clone与fork功能类似。在内核中三种函数的执行流程如下：</p>
<div style = "align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEBc958d4e5ba53bf36d8f1c91908b8483c?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="40%" height="40%"/>  

<ul>
<li>注：在Linux中fork()利用clone()来实现，在C程序中调用fork()函数会触发120号系统调用clone，不会触发2号系统调用fork！我猜应该是Linux中采用了写时复制技术，很多资源父子进程共享，所以不用全部拷贝，部份拷贝，其余资源共享即可，所以用clone系统调用。（以上过程在i386-32位平台上实现）</li>
</ul>
<p>因此，parent.c程序中执行fork和execve系统调用时，数据段中的str1字符串发生的改变如下：<br>1、刚进入main函数，父进程指向str1所在物理页面，且页面可写；</p>
<div style="align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEB220b71cadf3b1b5bac4278836e4a0316?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="70%" height="70%"/>  

<p>2、fork()函数执行后，父子进程共同指向str1物理页面，且页面只读；</p>
<div style="align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEB3721974e0a188301cfda36c6af2c619f?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="70%" height="70%"/>  

<p>3、子进程试图修改str1的内容，发生写时复制，str1拷贝到新内存区域防止篡改父进程数据；</p>
<div style="align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEB57c257d4ead121d8bc11a07729ae3391?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="70%" height="70%"/> 

<p>4、执行execve后子进程的mm_struct以及页目录项、页表项全部改变；</p>
<div style="align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEBbf788e3c7683fe13a889e12fcb327420?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="70%" height="70%"/> 

<p>如果将C程序中的fork()改为vfork()，则父子进程的mm_struct、页目录和页表项均共享，可以直接篡改对方进程的数据：</p>
<div style="align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEBeba8d4cdae87b5cff22f3f2d04def660?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="70%" height="70%"/> 

<h2 id="Execve系统调用"><a href="#Execve系统调用" class="headerlink" title="Execve系统调用"></a>Execve系统调用</h2><p>execve()函数是exec函数家族的一员，exec函数簇的6个函数功能类似，差别在于程序变量的表示方式和是否传入环境变量。exec会将可执行文件的绝对路径作为参数，把当前正在运行的用户的进程体（代码段、数据段、堆、栈、）用该可执行文件的进程体替换。<br>在shell终端输入一个可执行程序的文件名，shell程序会先用fork系统调用创建子进程，然后再调用execve系统调用，利用新的可执行文件的进程体替换fork出来的子进程的进程体，从而实现新进程执行完全不一样的新程序。<br>execve函数定义如下</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">execve</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *filename, <span class="type">char</span> *<span class="type">const</span> argv[], <span class="type">char</span> *<span class="type">const</span> envp[])</span></span>;</span><br></pre></td></tr></table></figure>
<p>三个参数分别是是可执行文件名、命令行参数和环境变量。execve()函数执行的主要轨迹如下：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">execve</span>()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">sys_execve</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">do_execve</span>()</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">do_execveat_common</span>()                        <span class="comment">//完成struct linux_binprm bprm初始化</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">load_elf_binary</span>()</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="built_in">load_elf_phdrs</span>();                   <span class="comment">//读取所有的程序头</span></span><br><span class="line">                    <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; e_phnum; i++)</span><br><span class="line">                    &#123;</span><br><span class="line">                        <span class="keyword">if</span> (e_type != PT_LOAD) <span class="keyword">continue</span>;</span><br><span class="line">                        <span class="built_in">elf_map</span>();            <span class="comment">//mmap代码段和数据段，并建立用户进程到文件页高速缓存</span></span><br><span class="line">                    &#125;                         <span class="comment">//的映射关系，同时创建vm_area_struct</span></span><br><span class="line">                    <span class="built_in">start_thread</span>()</span><br><span class="line">                    &#123;</span><br><span class="line">                        regs-&gt;ip = new_ip;              <span class="comment">//入口地址设置为elf header中的e_entry</span></span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;        </span><br></pre></td></tr></table></figure>
<p>exec函数簇的6个函数最终都会执行execve()系统调用，在sys_execve()服务例程中，do_execve()函数调用do_execveat_common()来完成结构体$\verb+struct linux_binprm bprm+$的初始化，用来记录可执行文件的信息。该函数还会调用path_look_up()和dentry_open()获得可执行文件相关的目录项对象、文件对象和inode对象（《深入理解Linux内核》），执行完该函数后，进入load_elf_binary()函数之前，$\verb+struct linux_binprm bprm+$中的内容如下所示：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  buf = <span class="string">&quot;\177ELF\001\001\001\003\000\000\000\000\000\000\000\000\002\000\003\000\001</span></span><br><span class="line"><span class="string">  \000\000\000\n\215\004\b4\000\000\000\f4\n\000\000\000\000\000\064\000 \000\006\000</span></span><br><span class="line"><span class="string">  (\000$\000!\000\001\000\000\000\000\000\000\000\000\200\004\b\000\200\004\bo\000\n</span></span><br><span class="line"><span class="string">  \000o\000\n\000\005\000\000\000\000\020\000\000\001\000\000\000X\017\n\000X\237\016</span></span><br><span class="line"><span class="string">  \bX\237\016\bH\000\000\314\063\000\000\006\000\000\000\000\020\000\000\004\000\000</span></span><br><span class="line"><span class="string">  \000\364\000\000\000\364\200\004\b&quot;</span>, vma = <span class="number">0xc011c528</span>,</span><br><span class="line">  vma_pages = <span class="number">2</span>, mm = <span class="number">0xc5cc7a40</span>, p = <span class="number">3221225460</span>, cred_prepared = <span class="number">1</span>,</span><br><span class="line">  cap_effective = <span class="number">1</span>, recursion_depth = <span class="number">1</span>, file = <span class="number">0xc7542300</span>,</span><br><span class="line">  cred = <span class="number">0xc6393640</span>, unsafe = <span class="number">0</span>, per_clear = <span class="number">0</span>, argc = <span class="number">0</span>, envc = <span class="number">0</span>,</span><br><span class="line">  filename = <span class="number">0xc75353d0</span> <span class="string">&quot;./child&quot;</span>, interp = <span class="number">0xc75353d0</span> <span class="string">&quot;./child&quot;</span>,</span><br><span class="line">  interp_flags = <span class="number">0</span>, interp_data = <span class="number">0</span>, loader = <span class="number">0</span>, exec = <span class="number">3221225460</span>&#125;</span><br></pre></td></tr></table></figure>
<p>其中buf为128字节，这些字节包含的是ELF文件格式的魔数和其他信息（即ELF Header），用八进制表示，可以看到开头的’\177ELF’就是前面说到的ELF Header的开头几个魔数。并且此时的vma(vm_area_Struct)只有栈段，mm(mm_struct)已经分配好了但是还没有初始化，将来会用新的mm替换当前的mm并且将会创建数据段和代码段的vm来插入当前的vma链表。会在接下来的load_elf_binary()函数中完成该过程。<br>此时内存的情况如下所示：</p>
<div style="align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEBa0ad675812fc28302e56120229572181?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="70%" height="70%"/> 

<p>load_elf_binary()函数为可执行文件的接口，执行的过程如下：</p>
<ul>
<li><p>1、动态创建一个结构体：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">struct</span> </span><br><span class="line"> &#123;</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">elfhdr</span> elf_ex;</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">elfhdr</span> interp_elf_ex;</span><br><span class="line"> &#125; *loc;</span><br></pre></td></tr></table></figure>
<p>然后从传入参数的bprm-&gt;buf中获得elf header的信息，并进行校验：魔数必须匹配，程序的类型必须为ET_EXEC或者ET_DYN，检查bprm-&gt;file-&gt;f_op-&gt;mmap，指向的文件是否已经映射到内存中；</p>
</li>
<li><p>2、查找解释器段<br>遍历所有程序头（一共6个），通过遍历每个段，找到PT_INTERP类型段，也即是解释器段，找到说明需要运行过程中的动态链接。“解释器”段实际上只是一个字符串，即解释器的文件名，最终记录在elf_interpreter变量中。另外child程序是静态编译的程序，不需要动态链接，也就没有解析器段。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">elf_phdata = <span class="built_in">load_elf_phdrs</span>(&amp;loc-&gt;elf_ex, bprm-&gt;file);</span><br><span class="line">elf_ppnt = elf_phdata;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; loc-&gt;elf_ex.e_phnum; i++) </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (elf_ppnt-&gt;p_type == PT_INTERP) </span><br><span class="line">      &#123;</span><br><span class="line">          ...</span><br><span class="line">	elf_interpreter = <span class="built_in">kmalloc</span>(elf_ppnt-&gt;p_filesz, GFP_KERNEL);</span><br><span class="line">          <span class="comment">//根据其位置的p_offset和大小p_filesz把整个&quot;解释器&quot;段的内容读入缓冲区</span></span><br><span class="line">	<span class="built_in">kernel_read</span>(bprm-&gt;file, elf_ppnt-&gt;p_offset, elf_interpreter,elf_ppnt-&gt;p_filesz);</span><br><span class="line">          <span class="comment">//struct *file类型的interpreter指针指向解释器段</span></span><br><span class="line">	interpreter = <span class="built_in">open_exec</span>(elf_interpreter);</span><br><span class="line">          <span class="comment">//读入其开头的128个字节，即解释器文件的elf头部。</span></span><br><span class="line">          <span class="built_in">kernel_read</span>(interpreter, <span class="number">0</span>, (<span class="type">void</span>*)&amp;loc-&gt;interp_elf_ex, <span class="built_in">sizeof</span>(loc-&gt;interp_elf_ex));</span><br><span class="line">          ...</span><br><span class="line">	<span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">elf_ppnt++;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li><p>3、清除前一个计算的所有资源，并分配新资源</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">flush_old_exec</span>(bprm);</span><br><span class="line">...</span><br><span class="line"><span class="built_in">setup_new_exec</span>(bprm);</span><br></pre></td></tr></table></figure>
</li>
<li><p>4、设置栈段<br>检查所有的程序段，如果某一个段的类型为PT_GNU_STACK，即栈段，那么检查标志并设定相应的值，然后调用setup_arg_pages()函数利用do_execve()生成的参数页面的信息，来设定本程序$\verb+struct linux_binprm bprm+$的栈顶地址，然后mm-&gt;start_stack &#x3D; bprm-&gt;p,将mm的栈的起始地址设定为bprm中栈顶指针指向的位置。</p>
</li>
</ul>
<p>跳过中间一些处理器相关的检查操作，直接来到ELF段载入阶段</p>
<ul>
<li><p>5、加载目标程序必须的段，即将ELF文件中的映像载入内存。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(i = <span class="number">0</span>, elf_ppnt = elf_phdata; i &lt; loc-&gt;elf_ex.e_phnum; i++, elf_ppnt++) </span><br><span class="line">  &#123;</span><br><span class="line"><span class="type">int</span> elf_prot = <span class="number">0</span>, elf_flags;</span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> k, vaddr;</span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> total_size = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">      <span class="comment">//搜索PT_LOAD段，也就是需要加载的段，只有代码段和数据段需要装入</span></span><br><span class="line"><span class="keyword">if</span> (elf_ppnt-&gt;p_type != PT_LOAD)</span><br><span class="line">	<span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">      <span class="comment">//检查标志、页面信息</span></span><br><span class="line"><span class="keyword">if</span> (elf_ppnt-&gt;p_flags &amp; PF_R) elf_prot |= PROT_READ;</span><br><span class="line"><span class="keyword">if</span> (elf_ppnt-&gt;p_flags &amp; PF_W) elf_prot |= PROT_WRITE;</span><br><span class="line"><span class="keyword">if</span> (elf_ppnt-&gt;p_flags &amp; PF_X) elf_prot |= PROT_EXEC;</span><br><span class="line"></span><br><span class="line">vaddr = elf_ppnt-&gt;p_vaddr;</span><br><span class="line"></span><br><span class="line">      <span class="comment">//设置e_flags标志</span></span><br><span class="line">      <span class="comment">//...</span></span><br><span class="line">      total_size = <span class="built_in">total_mapping_size</span>(elf_phdata, loc-&gt;elf_ex.e_phnum);</span><br><span class="line"></span><br><span class="line">      <span class="comment">//通过elf_map()来将用户虚拟地址load + vaddr和文件映像中的区域映射</span></span><br><span class="line"><span class="built_in">elf_map</span>(bprm-&gt;file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags, total_size);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>
<p>遍历所有段，如果该段是可加载段（child程序的可加载段就是代码段和数据段），就确定装入内存的地址load_bias + vaddr，并通过elf_map()来建立用户虚拟地址和文件映像中的区域映射。这里的load_bias是随机生成的偏移量，在映射到进程的虚拟地址空间时，栈、堆、解析器段的起始地址往往加上一个随机偏移量。因为整个程序的虚拟起始地址固定为0x08048000，敏感的栈区域容易被算出地址，被黑客利用。elf_map利用vm_map来建立虚拟地址到文件映像的映射，与mmap类似。<br>mmap会将文件从交换空间加载进内存，并为进程新创建一个vm_area_struct，同时建立vm_area_struct与进程段的映射关系，例如代码段的vm_area_struct的vm_start字段表明代码起始地址为0x08048000，vm_end字段表明代码段的结束位置。现在代码段和数据段已经加载到内存中了。并且代码段和数据段的vm_area_struct也已经设置好了，插入了进程的mmap指向的vma链表中：</p>
<div style="align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEBa5e38da11d4ff698e0aa0010fc73d156?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="70%" height="70%"/> 
</li>
<li><p>6、接下来是填写程序的入口地址。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">if</span> (elf_interpreter) </span><br><span class="line"> &#123;</span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> interp_map_addr = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">elf_entry = <span class="built_in">load_elf_interp</span>(&amp;loc-&gt;interp_elf_ex, interpreter, </span><br><span class="line">               &amp;interp_map_addr, load_bias, interp_elf_phdata);</span><br><span class="line"> &#125; </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> &#123;</span><br><span class="line">elf_entry = loc-&gt;elf_ex.e_entry;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>
<p>如果存在解释器段，就通过load_elf_interp()将其映像装入内存, 并把将来进入用户空间的入口地址elf_entry设置成解释器映像的入口地址，这样返回用户空间时先执行解析器程序，将需要的共享库(shared lib)映射到进程的虚拟地址空间中。如果没有解释器段，也就是child程序的情况，那么直接从ELF Header的e_entry字段获得程序入口地址（child文件映像的入口地址）。<br>此时入口地址应该是0x08048d0a!</p>
</li>
<li><p>7、执行前的准备<br>首先调用create_elf_tables()函数填写目标文件的命令行参数、环境变量等信息。这些信息需要复制到用户空间，使它们在PC跳转到解释器或目标映像的程序入口地址时出现在用户空间堆栈上。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">create_elf_tables</span>(bprm, &amp;loc-&gt;elf_ex, load_addr, interp_load_addr);</span><br></pre></td></tr></table></figure>
<p>vm_area_struct线性区结构体的映射由mmap完成，现在完成mm_struct的初始化。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"> current-&gt;mm-&gt;end_code = end_code;</span><br><span class="line"> current-&gt;mm-&gt;start_code = start_code;</span><br><span class="line"> current-&gt;mm-&gt;start_data = start_data;</span><br><span class="line"> current-&gt;mm-&gt;end_data = end_data;</span><br><span class="line"> current-&gt;mm-&gt;start_stack = bprm-&gt;p;</span><br><span class="line"> <span class="keyword">if</span> ((current-&gt;flags &amp; PF_RANDOMIZE) &amp;&amp; (randomize_va_space &gt; <span class="number">1</span>)) </span><br><span class="line"> &#123;</span><br><span class="line">current-&gt;mm-&gt;brk = current-&gt;mm-&gt;start_brk = <span class="built_in">arch_randomize_brk</span>(current-&gt;mm);</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure></li>
<li><p>8、调用start_thread()函数准备执行此ELF程序<br>该函数是一个与体系结构相关的函数，在i386中其核心函数如下：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">regs-&gt;fs = <span class="number">0</span>;</span><br><span class="line">regs-&gt;ds = __USER_DS;</span><br><span class="line">regs-&gt;es = __USER_DS;</span><br><span class="line">regs-&gt;ss = __USER_DS;</span><br><span class="line">regs-&gt;cs = __USER_CS;</span><br><span class="line">regs-&gt;ip = new_ip;</span><br><span class="line">regs-&gt;sp = new_sp;</span><br><span class="line">regs-&gt;flags = X86_EFLAGS_IF;</span><br></pre></td></tr></table></figure>
<p>最后，函数跳转到regs-&gt;ip处(地址0x8048d0a)执行，execve系统调用结束。</p>
</li>
</ul>
<p>最终内存的情况如下图所示：</p>
<div style="align: center">
<img data-src="https://note.youdao.com/yws/api/personal/file/WEBaa532b54422051cd4217f2017b02d9ec?method=download&shareKey=69113f8f61e335d1864757cf6d288929" width="70%" height="70%"/> 

<p>至此，程序的创建和可执行文件的加载过程全部结束！</p>

    </div>

    
    
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>虎王
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://chudod.gitee.io/works/2022/05/06/OS_ELF_execve/" title="Linux程序执行与进程创建">https://chudod.gitee.io/works/2022/05/06/OS_ELF_execve/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>

        

  <div class="followme">
    <p>欢迎关注我的其它发布渠道</p>

    <div class="social-list">

        <div class="social-item">
          <a target="_blank" class="social-link" href="/images/wechat_channel.jpg">
            <span class="icon">
              <i class="fab fa-weixin"></i>
            </span>

            <span class="label">WeChat</span>
          </a>
        </div>

        <div class="social-item">
          <a target="_blank" class="social-link" href="/atom.xml">
            <span class="icon">
              <i class="fa fa-rss"></i>
            </span>

            <span class="label">RSS</span>
          </a>
        </div>
    </div>
  </div>


      <footer class="post-footer">
          <div class="post-tags">
              <a href="/works/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" rel="tag"># 操作系统</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/works/2022/04/28/Triggered_Operation/" rel="prev" title="使用触发操作卸载集合通信">
      <i class="fa fa-chevron-left"></i> 使用触发操作卸载集合通信
    </a></div>
      <div class="post-nav-item">
    <a href="/works/2022/05/11/Russian_Vocabulary/" rel="next" title="Русские Слова(俄语单词)">
      Русские Слова(俄语单词) <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E7%A8%8B%E5%BA%8F%E7%9A%84%E7%BC%96%E8%AF%91%E4%B8%8E%E6%89%A7%E8%A1%8C"><span class="nav-number">1.</span> <span class="nav-text">一、程序的编译与执行</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Program-Header"><span class="nav-number">1.1.</span> <span class="nav-text">Program Header</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ELF%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F"><span class="nav-number">1.2.</span> <span class="nav-text">ELF文件格式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#ELF%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E6%95%B4%E4%BD%93%E8%A7%86%E5%9B%BE"><span class="nav-number">1.2.1.</span> <span class="nav-text">ELF文件格式整体视图</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link"><span class="nav-number">1.2.1.1.</span> <span class="nav-text">ELF文件格式视图</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#ELF-Header%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84"><span class="nav-number">1.2.2.</span> <span class="nav-text">ELF Header数据结构</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link"><span class="nav-number">1.2.2.1.</span> <span class="nav-text">e_ident[16]数组</span></a></li><li class="nav-item nav-level-4"><a class="nav-link"><span class="nav-number">1.2.2.2.</span> <span class="nav-text">struct Elf32_Ehdr成员定义</span></a></li><li class="nav-item nav-level-4"><a class="nav-link"><span class="nav-number">1.2.2.3.</span> <span class="nav-text">struct Elf32_Phdr成员定义</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%9E%E9%AA%8C%E7%A8%8B%E5%BA%8F%E5%AE%9E%E4%BE%8B"><span class="nav-number">1.2.3.</span> <span class="nav-text">实验程序实例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#ELF-Header%E5%AE%9E%E4%BE%8B"><span class="nav-number">1.2.4.</span> <span class="nav-text">ELF Header实例</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link"><span class="nav-number">1.2.4.1.</span> <span class="nav-text">child文件的ELF Header信息</span></a></li><li class="nav-item nav-level-4"><a class="nav-link"><span class="nav-number">1.2.4.2.</span> <span class="nav-text">child文件的Program Header信息</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%88%9B%E5%BB%BA%E4%B8%8E%E7%A8%8B%E5%BA%8F%E5%8A%A0%E8%BD%BD"><span class="nav-number">2.</span> <span class="nav-text">进程的创建与程序加载</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%95%B4%E4%BD%93%E8%A7%86%E5%9B%BE"><span class="nav-number">2.1.</span> <span class="nav-text">整体视图</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Fork%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8"><span class="nav-number">2.2.</span> <span class="nav-text">Fork系统调用</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Execve%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8"><span class="nav-number">2.3.</span> <span class="nav-text">Execve系统调用</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="虎王"
      src="/works/images/avatar.png">
  <p class="site-author-name" itemprop="name">虎王</p>
  <div class="site-description" itemprop="description">喜欢造飞机导弹和计算机的大学生</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/works/archives/">
        
          <span class="site-state-item-count">21</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/works/categories/">
          
        <span class="site-state-item-count">13</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/works/tags/">
          
        <span class="site-state-item-count">12</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/DoD-Chu/" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;DoD-Chu&#x2F;" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:1368095113@qq.com" title="E-Mail → mailto:1368095113@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://www.zhihu.com/people/pu-ti-shan-cheng-zhu" title="知乎 → https:&#x2F;&#x2F;www.zhihu.com&#x2F;people&#x2F;pu-ti-shan-cheng-zhu" rel="noopener" target="_blank"><i class="fab fa-stack-overflow fa-fw"></i>知乎</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      其他站点
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://www.zhihu.com/people/pu-ti-shan-cheng-zhu" title="https:&#x2F;&#x2F;www.zhihu.com&#x2F;people&#x2F;pu-ti-shan-cheng-zhu" rel="noopener" target="_blank">知乎主页</a>
        </li>
    </ul>
  </div>

      </div>
        <div class="back-to-top motion-element">
          <i class="fa fa-arrow-up"></i>
          <span>0%</span>
        </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; Fri Mar 25 2022 08:00:00 GMT+0800 (中国标准时间) – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">虎王</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

<div class="theme-info">
  <div class="powered-by"></div>
  <span class="post-count">博客全站共30.4k字</span>
</div>


    <script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <span id="busuanzi_container_site_pv">总访问量<span id="busuanzi_value_site_pv"></span>次</span>
    <span class="post-meta-divider">|</span>
    <span id="busuanzi_container_site_uv">总访客数<span id="busuanzi_value_site_uv"></span>人</span>
    <span class="post-meta-divider">|</span>
<!-- 不蒜子计数初始值纠正 -->
<script>
$(document).ready(function() {

    var int = setInterval(fixCount, 50);  // 50ms周期检测函数
    var countOffset = 20000;  // 初始化首次数据

    function fixCount() {            
       if (document.getElementById("busuanzi_container_site_pv").style.display != "none")
        {
            $("#busuanzi_value_site_pv").html(parseInt($("#busuanzi_value_site_pv").html()) + countOffset); 
            clearInterval(int);
        }                  
        if ($("#busuanzi_container_site_pv").css("display") != "none")
        {
            $("#busuanzi_value_site_uv").html(parseInt($("#busuanzi_value_site_uv").html()) + countOffset); // 加上初始数据 
            clearInterval(int); // 停止检测
        }  
    }
       	
});
</script> 

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  
  <script color='0,0,255' opacity='0.5' zIndex='-1' count='99' src="/works/lib/canvas-nest/canvas-nest.min.js"></script>
  <script src="/works/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/lozad@1/dist/lozad.min.js"></script>
  <script src="/works/lib/velocity/velocity.min.js"></script>
  <script src="/works/lib/velocity/velocity.ui.min.js"></script>

<script src="/works/js/utils.js"></script>

<script src="/works/js/motion.js"></script>


<script src="/works/js/schemes/pisces.js"></script>


<script src="/works/js/next-boot.js"></script>

<script src="/works/js/bookmark.js"></script>




  
  <script>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>




  
<script src="//cdn.jsdelivr.net/npm/algoliasearch@4/dist/algoliasearch-lite.umd.js"></script>
<script src="//cdn.jsdelivr.net/npm/instantsearch.js@4/dist/instantsearch.production.min.js"></script>
<script src="/works/js/algolia-search.js"></script>










<script>
document.querySelectorAll('.pdfobject-container').forEach(element => {
  let url = element.dataset.target;
  let pdfOpenParams = {
    navpanes : 0,
    toolbar  : 0,
    statusbar: 0,
    pagemode : 'thumbs',
    view     : 'FitH'
  };
  let pdfOpenFragment = '#' + Object.entries(pdfOpenParams).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join('&');
  let fullURL = `/works/lib/pdf/web/viewer.html?file=${encodeURIComponent(url)}${pdfOpenFragment}`;

  if (NexT.utils.supportsPDFs()) {
    element.innerHTML = `<embed class="pdfobject" src="${url + pdfOpenFragment}" type="application/pdf" style="height: ${element.dataset.height};">`;
  } else {
    element.innerHTML = `<iframe src="${fullURL}" style="height: ${element.dataset.height};" frameborder="0"></iframe>`;
  }
});
</script>


<script>
if (document.querySelectorAll('pre.mermaid').length) {
  NexT.utils.getScript('//cdn.jsdelivr.net/npm/mermaid@8/dist/mermaid.min.js', () => {
    mermaid.initialize({
      theme    : 'forest',
      logLevel : 3,
      flowchart: { curve     : 'linear' },
      gantt    : { axisFormat: '%m/%d/%Y' },
      sequence : { actorMargin: 50 }
    });
  }, window.mermaid);
}
</script>


  

  
      

<script>
  if (typeof MathJax === 'undefined') {
    window.MathJax = {
      loader: {
        source: {
          '[tex]/amsCd': '[tex]/amscd',
          '[tex]/AMScd': '[tex]/amscd'
        }
      },
      tex: {
        inlineMath: {'[+]': [['$', '$']]},
        tags: 'ams'
      },
      options: {
        renderActions: {
          findScript: [10, doc => {
            document.querySelectorAll('script[type^="math/tex"]').forEach(node => {
              const display = !!node.type.match(/; *mode=display/);
              const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display);
              const text = document.createTextNode('');
              node.parentNode.replaceChild(text, node);
              math.start = {node: text, delim: '', n: 0};
              math.end = {node: text, delim: '', n: 0};
              doc.math.push(math);
            });
          }, '', false],
          insertedScript: [200, () => {
            document.querySelectorAll('mjx-container').forEach(node => {
              let target = node.parentNode;
              if (target.nodeName.toLowerCase() === 'li') {
                target.parentNode.classList.add('has-jax');
              }
            });
          }, '', false]
        }
      }
    };
    (function () {
      var script = document.createElement('script');
      script.src = '//cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js';
      script.defer = true;
      document.head.appendChild(script);
    })();
  } else {
    MathJax.startup.document.state(0);
    MathJax.texReset();
    MathJax.typeset();
  }
</script>

    

  

</body>
</html>
